﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using MobileSales.Server.Database;
using MobileSales.Common.Logger;

namespace MobileSales.Server.Services
{
    public class OrderService : ServiceBase,IOrderService
    {
        #region Order management

        #region GetOrder
        public Model.Orders.Order GetOrder(int orderId)
        {
            this.ValidateToken();
            Order dbOrder = entities.Orders.Where(x => x.OrderId.Equals(orderId)).FirstOrDefault();
            if (dbOrder != null)
            {
                Model.Orders.Order order = new Model.Orders.Order()
                {
                    ClientId = dbOrder.ClientId,
                    Date = dbOrder.Date,
                    Id = dbOrder.OrderId,
                    Status = this.GetOrderStatus(dbOrder.OrderStatusId),
                    Items = this.GetOrderItemList(dbOrder.OrderId)
                };
                return order;
            }
            else
                CLogger.LogDebug("Order not found");
            return null;
        } 
        #endregion

        #region GetOrderList
        public IEnumerable<Model.Orders.Order> GetOrderList()
        {
            return this.GetFilteredOrderList(null, null, null, null);
        } 
        #endregion

        #region GetFilteredOrderList
        public IEnumerable<Model.Orders.Order> GetFilteredOrderList(int? orderStatusId, int? orderClientId, DateTime? startDate, DateTime? endDate)
        {
            this.ValidateToken();
            IEnumerable<Order> dbOrders = entities.Orders.OrderByDescending(x => x.Date);
            if (orderStatusId.HasValue)
                dbOrders = dbOrders.Where(x => x.OrderStatusId.Equals(orderStatusId.Value));
            if (orderClientId.HasValue)
                dbOrders = dbOrders.Where(x => x.ClientId.Equals(orderClientId.Value));
            if (startDate.HasValue)
                dbOrders = dbOrders.Where(x => x.Date >= startDate);
            if (endDate.HasValue)
                dbOrders = dbOrders.Where(x => x.Date <= endDate);

            if (dbOrders != null)
            {
                List<Model.Orders.Order> list = new List<Model.Orders.Order>();
                foreach (var dbOrder in dbOrders)
                {
                    Model.Orders.Order order = new Model.Orders.Order()
                    {
                        ClientId = dbOrder.ClientId,
                        Date = dbOrder.Date,
                        Id = dbOrder.OrderId,
                        Status = this.GetOrderStatus(dbOrder.OrderStatusId),
                        Items = this.GetOrderItemList(dbOrder.OrderId)
                    };
                    list.Add(order);
                }
                return list;
            }
            else
                CLogger.LogDebug("Could not get order list");
            return null;
        } 
        #endregion

        #region StoreOrder
        public void StoreOrder(Model.Orders.Order order)
        {
            this.ValidateToken();

            Order dbOrder = null;
            if (order.Id != 0)
            {
                dbOrder = entities.Orders.Where(x => x.OrderId.Equals(order.Id)).FirstOrDefault();
                if (dbOrder == null)
                    this.Raise("Order not found");
                
                bool hasDocument = entities.Documents.Count(x => x.OrderId.Equals(order.Id)) == 1;
                if (hasDocument)
                    this.Raise("Order has been completed");
            }
            else
            {
                dbOrder = new Order();
            }
            dbOrder.ClientId = order.ClientId;
            dbOrder.Date = order.Date;
            dbOrder.OrderStatusId = order.Status.Id;
            if (order.Id == 0)
            {
                dbOrder.CreatorId = this.GetEmployeeIdFromToken();
                entities.Orders.AddObject(dbOrder);
                dbOrder.Date = DateTime.Now;
            }
            entities.SaveChanges();

            if (order.Items != null)
            {
                foreach (var orderItem in order.Items)
                {
                    orderItem.OrderId = dbOrder.OrderId;
                    this.StoreOrderItem(orderItem);
                }
            }
            this.NotifyAll(Util.ServiceType.OrderService, "GetOrder", dbOrder.OrderId);
        } 
        #endregion

        #region DeleteOrder
        public void DeleteOrder(int orderId)
        {
            this.ValidateToken();
            bool hasDocument = entities.Documents.Count(x => x.OrderId.Equals(orderId)) == 1;
            if (hasDocument)
                this.Raise("Order has been completed");

            Order dbOrder = entities.Orders.Where(x => x.OrderId.Equals(orderId)).FirstOrDefault();
            if (dbOrder != null)
            {
                entities.Orders.DeleteObject(dbOrder);
                entities.SaveChanges();
                this.NotifyAll(Util.ServiceType.OrderService, "DeleteOrder", orderId);
            }
            else
                this.Raise("Order not found");
        }  
        #endregion

        #endregion

        #region Order item management

        #region GetOrderItem
        public Model.Orders.OrderItem GetOrderItem(int orderItemId)
        {
            this.ValidateToken();
            OrderElement dbOrderItem = entities.OrderElements.Where(x => x.OrderElementId.Equals(orderItemId)).FirstOrDefault();
            if (dbOrderItem != null)
            {
                Model.Orders.OrderItem orderItem = new Model.Orders.OrderItem()
                {
                    Id = dbOrderItem.OrderElementId,
                    Product = new ProductService().GetProduct(dbOrderItem.ProductId),
                    OrderId = dbOrderItem.OrderId,
                    Quantity = dbOrderItem.Quantity
                };
                return orderItem;
            }
            else
                CLogger.LogDebug("Order item not found");
            return null;
        } 
        #endregion

        #region GetOrderItemList
        public IEnumerable<Model.Orders.OrderItem> GetOrderItemList(int orderId)
        {
            this.ValidateToken();
            IEnumerable<OrderElement> dbOrderItems = entities.OrderElements.Where(x => x.OrderId.Equals(orderId));
            if (dbOrderItems != null)
            {
                List<Model.Orders.OrderItem> list = new List<Model.Orders.OrderItem>();
                foreach (var dbOrderItem in dbOrderItems)
                {
                    Model.Orders.OrderItem orderItem = new Model.Orders.OrderItem()
                    {
                        Id = dbOrderItem.OrderElementId,
                        Product = new ProductService().GetProduct(dbOrderItem.ProductId),
                        OrderId = dbOrderItem.OrderId,
                        Quantity = dbOrderItem.Quantity
                    };
                    list.Add(orderItem);
                }
                return list;
            }
            else
                CLogger.LogDebug("Could not get order item list");
            return null;
        } 
        #endregion

        #region StoreOrderItem
        public void StoreOrderItem(Model.Orders.OrderItem orderItem)
        {
            this.ValidateToken();

            bool hasDocument = entities.Documents.Count(x => x.OrderId.Equals(orderItem.OrderId)) == 1;
            if (hasDocument)
                this.Raise("Order has been completed");

            OrderElement dbOrderItem = null;
            bool similarExist = false;
            if (orderItem.Id != 0)
            {
                dbOrderItem = entities.OrderElements.Where(x => x.OrderElementId.Equals(orderItem.Id)).FirstOrDefault();
                if (dbOrderItem == null)
                    this.Raise("Order item not found");
            }
            else
            {
                dbOrderItem = entities.OrderElements.Where(x => x.OrderId.Equals(orderItem.OrderId) && x.ProductId.Equals(orderItem.Product.Id)).FirstOrDefault();
                if (dbOrderItem != null) 
                    similarExist = true;
                else 
                    dbOrderItem = new OrderElement();
            }
            dbOrderItem.OrderId = orderItem.OrderId;
            dbOrderItem.ProductId = orderItem.Product.Id;
            if (similarExist)
                dbOrderItem.Quantity += orderItem.Quantity;
            else
                dbOrderItem.Quantity = orderItem.Quantity;

            if (orderItem.Id == 0 && !similarExist)
                entities.OrderElements.AddObject(dbOrderItem);
            entities.SaveChanges();
            this.NotifyAll(Util.ServiceType.OrderService, "GetOrder", dbOrderItem.OrderId);
        } 
        #endregion

        #region DeleteOrderItem
        public void DeleteOrderItem(int orderItemId)
        {
            this.ValidateToken();
            OrderElement dbOrderItem = entities.OrderElements.Where(x => x.OrderElementId.Equals(orderItemId)).FirstOrDefault();

            bool hasDocument = entities.Documents.Count(x => x.OrderId.Equals(dbOrderItem.OrderId)) == 1;
            if (hasDocument)
                this.Raise("Order has been completed");

            int orderId = dbOrderItem.OrderId;
            if (dbOrderItem != null)
            {
                entities.OrderElements.DeleteObject(dbOrderItem);
                entities.SaveChanges();
                this.NotifyAll(Util.ServiceType.OrderService, "GetOrder", orderId);
            }
            else
                this.Raise("Order item not found");
        }  
        #endregion

        #endregion

        #region Order status management

        #region GetOrderStatus
        public Model.Orders.OrderStatus GetOrderStatus(int orderStatusId)
        {
            this.ValidateToken();
            OrderStatus dbOrderStatus = entities.OrderStatuses.Where(x => x.OrderStatusId.Equals(orderStatusId)).FirstOrDefault();
            if (dbOrderStatus != null)
            {
                Model.Orders.OrderStatus orderStatus = new Model.Orders.OrderStatus
                {
                    Id = dbOrderStatus.OrderStatusId,
                    Name = dbOrderStatus.StatusName
                };
                return orderStatus;
            }
            else
                CLogger.LogDebug("Order status not found");
            return null;
        } 
        #endregion

        #region GetOrderStatusList
        public IEnumerable<Model.Orders.OrderStatus> GetOrderStatusList()
        {
            this.ValidateToken();
            IEnumerable<OrderStatus> dbOrderStatuses = entities.OrderStatuses;
            if (dbOrderStatuses != null)
            {
                List<Model.Orders.OrderStatus> list = new List<Model.Orders.OrderStatus>();
                foreach (var dbOrderStatus in dbOrderStatuses)
                {
                    Model.Orders.OrderStatus orderStatus = new Model.Orders.OrderStatus
                    {
                        Id = dbOrderStatus.OrderStatusId,
                        Name = dbOrderStatus.StatusName
                    };
                    list.Add(orderStatus);
                }
                return list;
            }
            else
                CLogger.LogDebug("Could not get order status list");
            return null;
        } 
        #endregion

        #region StoreOrderStatus
        public void StoreOrderStatus(Model.Orders.OrderStatus orderStatus)
        {
            this.ValidateToken();
            OrderStatus dbOrderStatus = null;
            if (orderStatus.Id != 0)
            {
                dbOrderStatus = entities.OrderStatuses.Where(x => x.OrderStatusId.Equals(orderStatus.Id)).FirstOrDefault();
                if (dbOrderStatus == null)
                    this.Raise("Order status not found");
            }
            else
            {
                dbOrderStatus = new OrderStatus();
            }
            dbOrderStatus.StatusName = orderStatus.Name;
            if (orderStatus.Id == 0)
                entities.OrderStatuses.AddObject(dbOrderStatus);
            entities.SaveChanges();
            this.NotifyAll(Util.ServiceType.OrderService, "GetOrderStatus", dbOrderStatus.OrderStatusId);
        } 
        #endregion

        #region DeleteOrderStatus
        public void DeleteOrderStatus(int orderStatusId)
        {
            this.ValidateToken();
            OrderStatus dbOrderStatus = entities.OrderStatuses.Where(x => x.OrderStatusId.Equals(orderStatusId)).FirstOrDefault();
            if (dbOrderStatus != null)
            {
                entities.OrderStatuses.DeleteObject(dbOrderStatus);
                entities.SaveChanges();
                this.NotifyAll(Util.ServiceType.OrderService, "DeleteOrderStatus", orderStatusId);
            }
            else
                this.Raise("Order status not found");
        }  
        #endregion

        #endregion
    }
}
